package com.sczmgk.frame.http;

import android.os.Handler;

import com.sczmgk.hotline.utils.MyLog;

import org.json.JSONObject;

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.net.ssl.HttpsURLConnection;

public class HttpThread extends Thread {

	private static final String TAG = HttpThread.class.getSimpleName();

	private HttpRequest mHttpRequest;

	private HttpThreadListener mHttpThreadListener;
	private HttpURLConnection urlConnection;
	private static boolean hasTrustAllHosts = false;
	
	public HttpThread(HttpThreadListener httpThreadListener) {
		this.mHttpThreadListener = httpThreadListener;
	}

	@Override
	public void run() {


		MyLog.i(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" HttpThread : " + this.getName() + "!! ");

		while (true) {
			synchronized (mHttpThreadListener) {
				mHttpRequest = mHttpThreadListener.getHttpRequest();
				if(mHttpRequest == null){
					mHttpThreadListener.requestWait(this);
					continue;
				}
			}
			try {
				HttpResponse httpResponse = mHttpRequest.onPreExecute();
				if(httpResponse!=null){
					postHttpFinish(mHttpRequest,httpResponse);
				}
				else{
					MyLog.i(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" HttpThread : " + this.getName() + "  寮�璇锋眰==> "
							+ mHttpRequest.getUrl());
					postHttpBegin(mHttpRequest);
					httpResponse = httpConnect(mHttpRequest);
					if(httpResponse!=null){
						HttpRequest httpContinueRequest = null;
						
						while((httpContinueRequest = httpResponse.getHttpContinueRequest()) !=null){
							MyLog.i(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" HttpThread : " + this.getName() + "  寮�杩炵画璇锋眰==> "
									+ mHttpRequest.getUrl());
							httpResponse = httpConnect(httpContinueRequest);
						}
					}
					postHttpFinish(mHttpRequest,httpResponse);
					if(httpResponse.getStateCode()== HttpResponse.STATE_SUCCESS){
						mHttpRequest.onPostExecute(true);
					}else{
						mHttpRequest.onPostExecute(false);
					}
					
				}
			}
			catch (HttpOperateException ex){
				ex.printStackTrace();
				throw new RuntimeException("宕╂簝浜�");
			}
			catch (Exception e) {
				e.printStackTrace();
				postHttpError();
				MyLog.e(TAG,
						"httpFrame  threadName:"+ Thread.currentThread().getName()+" HttpThread    ==> "
								+ mHttpRequest.getUrl() + " Exception:"
								+ e.toString());

			} 
			catch (OutOfMemoryError e) {
				e.printStackTrace();
				postHttpError();
				MyLog.e(TAG,
						"httpFrame  threadName:"+ Thread.currentThread().getName()+" ====");
			}
			finally {
				mHttpThreadListener.finishHttpRequest(mHttpRequest);
				mHttpRequest = null;
				urlConnection = null;
			}

		}
			
	}
	
	private void postHttpError(){
		try {
			postHttpFinish(mHttpRequest, mHttpRequest.
					createErrorResponse(HttpResponse.STATE_FAILED, mHttpRequest));
		} catch (HttpOperateException e1) {
			e1.printStackTrace();
			throw new RuntimeException("宕╂簝浜�");
		}
		mHttpRequest.onPostExecute(false);
	}
	private void postHttpBegin(final HttpRequest httpRequest) throws HttpOperateException {
		updateHttpBegin(httpRequest);
		
		List<HttpRequest> sameRequestList = httpRequest.getSameRequestList();
		for(int i=0;i<sameRequestList.size();i++){
			updateHttpBegin(sameRequestList.get(i));
		}
		
	}
	private void updateHttpBegin(final HttpRequest httpRequest) throws HttpOperateException {
		
		if(httpRequest.getHttpListener() instanceof HttpListener){
			Handler handler = httpRequest.getHandler();
			final HttpListener httpLinstener = (HttpListener) httpRequest.getHttpListener();
			if(handler!=null){
				handler.post(new Runnable() {
					
					@Override
					public void run() {
						MyLog.i(TAG, "httpFrame updateHttpBegin    "+httpRequest.getUrl());
						httpLinstener.onHttpBegin(httpRequest);
					}
				});
			}else{
				MyLog.i(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" updateHttpBegin  -  "+httpRequest.getUrl());
				try{
					httpLinstener.onHttpBegin(httpRequest);
				}catch(Exception ex){
					throw new HttpOperateException(ex);
				}
			}
		}
		
	}
	public static void postHttpFinish(final HttpRequest httpRequest,
			final HttpResponse httpResponse) throws HttpOperateException {
		try {
			HttpSimpleListener simpleListener = HttpConnector.getHttpFilterListener();
			if(simpleListener!=null){
				simpleListener.onHttpFinish(httpResponse);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
		HttpThread.updateHttpFinish(httpRequest,httpResponse,false);
		
		List<HttpRequest> sameRequestList = httpRequest.getSameRequestList();
		for(int i=0;i<sameRequestList.size();i++){
			HttpThread.updateHttpFinish(sameRequestList.get(i),httpResponse,true);
		}
	}
	
	public static void updateHttpFinish(final HttpRequest httpRequest,
										final HttpResponse httpResponse, final boolean isSameRequest) throws HttpOperateException {
		if(httpRequest.getHttpListener() instanceof HttpSimpleListener){
			Handler handler = httpRequest.getHandler();
			final HttpSimpleListener httpLinstener = (HttpSimpleListener) httpRequest.getHttpListener();
			if(handler!=null){
				handler.post(new Runnable() {
					
					@Override
					public void run() {
						MyLog.i(TAG, "httpFrame updateHttpFinish UI绾跨▼     httpResponse:"+httpResponse.toString());
						if(isSameRequest){
							httpLinstener.onHttpFinish(httpResponse.createSameResponse(httpRequest));
						}else{
							httpLinstener.onHttpFinish(httpResponse);
						}
					}
				});
			}else{
				MyLog.i(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+"  updateHttpFinish  httpResponse:"+httpResponse.toString());
				try{
					if(isSameRequest){
						httpLinstener.onHttpFinish(httpResponse.createSameResponse(httpRequest));
					}else{
						httpLinstener.onHttpFinish(httpResponse);
					}
				}catch(Exception ex){
					throw new HttpOperateException(ex);
				}
			}
		}
	}
	public static void postUploadProgress(final HttpRequest httpRequest, long hasReadBytes, long fileContentLength) throws HttpOperateException {
		
		final float percent = ((hasReadBytes / (float) fileContentLength) * 100f);
		final long sumLength = fileContentLength;
		final long downloadLength = hasReadBytes;
		
		HttpThread.updateUploadProgress(httpRequest, percent, downloadLength, sumLength);
		
		List<HttpRequest> sameRequestList = httpRequest.getSameRequestList();
		for(int i=0;i<sameRequestList.size();i++){
			MyLog.w(TAG, "httpFrame postUploadProgress 绱姞鐩戝惉鍥炶皟");
			HttpThread.updateUploadProgress(sameRequestList.get(i), percent, downloadLength, sumLength);
		}
	}
	
	public static void updateUploadProgress(final HttpRequest httpRequest,
			final float percent,final long downloadLength,final long sumLength) throws HttpOperateException {
		MyLog.i(TAG, "httpFrame updateProgress 姝ｅ湪澶勭悊鍥炶皟  Length:"+downloadLength+"  sumLength:"+sumLength);
		if(httpRequest.getHttpListener() instanceof HttpProgressListener){
			Handler handler = httpRequest.getHandler();
			final HttpProgressListener httpLinstener = (HttpProgressListener) httpRequest.getHttpListener();
			if(handler!=null){
				handler.post(new Runnable() {
					
					@Override
					public void run() {
						MyLog.i(TAG, "httpFrame updateProgress 鍥炶皟 UI绾跨▼   Length:"+downloadLength+"  sumLength:"+sumLength);
						httpLinstener.onProgress(httpRequest, percent, downloadLength, sumLength);
					}
				});
			}else{
				MyLog.i(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" updateProgress 鍥炶皟 闈濽I绾跨▼  Length:"+downloadLength+"  sumLength:"+sumLength);
				try{
					httpLinstener.onProgress(httpRequest, percent, downloadLength, sumLength);
				}catch(Exception ex){
					throw new HttpOperateException(ex);
				}
			}
		}
	}

	private HttpResponse httpConnect(HttpRequest httpRequest) throws Exception {
		openConnection(httpRequest);

		setHttpProperty(httpRequest);
		handleParam(httpRequest);

		MyLog.i(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" HttpThread  鍑嗗寮�寤虹珛杩炴帴");
		urlConnection.connect();
		MyLog.i(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" HttpThread  宸茬粡鎴愬姛寤虹珛杩炴帴");
		if(handleResponseHead()){
			HttpCookie.getResponseCookies(urlConnection);

			return handleResponseData(httpRequest);
		}
		return null;
	}
	private void openConnection(HttpRequest httpRequest) throws Exception {
		String urlString = "";
		if (HttpRequest.REQUEST_METHOD_POST.equals(httpRequest
				.getRequestMethod())) {
			urlString = HttpHelper.initURL(httpRequest.getUrl(),httpRequest.getPostUrlParamData());
		} else {
			urlString = HttpHelper.initURL(httpRequest.getUrl(),
					httpRequest.getParamData());
		}
		
		if(urlString==null){
			throw new Exception("璇锋眰url鍦板潃閿欒  url:"+urlString);
		}
		
		URL url = new URL(urlString);

		if (urlString.startsWith("https")) {

			if(!hasTrustAllHosts){
				HttpHelper.trustAllHosts();
				hasTrustAllHosts = true;
			}
			urlConnection = (HttpsURLConnection) url.openConnection();
			((HttpsURLConnection)urlConnection).setHostnameVerifier(HttpHelper.DO_NOT_VERIFY);
		} else {
			urlConnection = (HttpURLConnection) url.openConnection();

		}

//		urlConnection.setDoOutput(true);
		urlConnection.setDoInput(true);
	}
	private void setHttpProperty(HttpRequest httpRequest) throws Exception {
		urlConnection.setConnectTimeout((int) httpRequest.getConnectTimeout());
		urlConnection.setReadTimeout((int) httpRequest.getReadTimeout());

		String cookie = null;
		Object obj = HttpCookie.getRequestCookies(httpRequest.getUrl());
		if (obj != null)
			cookie = obj.toString();
		urlConnection.setRequestProperty("Cookie", cookie);
		urlConnection.setRequestProperty("connection", "keep-alive");
		urlConnection.setRequestProperty(
						"Accept",
						"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
		urlConnection.setRequestProperty("Accept-Language", "zh-CN");
		urlConnection.setRequestProperty("Charset", "UTF-8");
		
		httpRequest.onPreExecute(urlConnection);
		HashMap<String, Object> paramMap = httpRequest.getHeaderMap();
		
		if(paramMap != null){
			Iterator<String> it = paramMap.keySet().iterator();
			while (it.hasNext()) {
				String key = it.next();
				obj = paramMap.get(key);
				String valuse = "";
				if(obj instanceof byte[]){
					valuse = new String((byte[])obj);
				}else{
					valuse = ""+obj;
				}
				urlConnection.setRequestProperty(key, valuse);
			}
		}
		setGeneralHttpProperty();
	}
	private void setGeneralHttpProperty(){
		urlConnection.addRequestProperty("User-Agent", ApplicationUtil.getAppInfo());
	}
	private void handleParam(HttpRequest httpRequest) throws Exception {
		if (HttpRequest.REQUEST_METHOD_POST.equals(httpRequest
				.getRequestMethod())) {
			MyLog.d(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" handleParam  POST ");
			urlConnection.setDoOutput(true);

			urlConnection.setRequestMethod("POST");
			
			Object paramData = httpRequest.getParamData();
			
			if(paramData==null){
				return;
			}
			if(paramData instanceof byte[]){
				byte[] bytes = (byte[])paramData;
				OutputStream out = new DataOutputStream(urlConnection.getOutputStream());
				out.write(bytes, 0, bytes.length);
				out.close();
			}
			else if(paramData instanceof JSONObject){
				JSONObject paramJson = (JSONObject) paramData;
				String jsonStr = paramJson.toString();
				PrintStream send = new PrintStream(urlConnection.getOutputStream());
				send.print(httpRequest.getParamData());
				send.close();
				MyLog.d(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" handleParam  POST JsonParam :"+jsonStr);
			}
			else if(paramData instanceof HashMap){
				String paramMap = HttpHelper.getRequestURLParam(paramData);
				PrintStream send = new PrintStream(urlConnection.getOutputStream());
				send.print(paramMap);
				send.close();
				MyLog.d(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" handleParam  POST mapParam :"+paramMap);
			}
			else if(paramData instanceof HttpWriteParamCallback){
				((HttpWriteParamCallback)paramData).writeParam(urlConnection);
				MyLog.d(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" handleParam  POST paramData  ");
			}
			else{
				PrintStream send = new PrintStream(urlConnection.getOutputStream());
				send.print(httpRequest.getParamData());
				send.close();
			}
			
			MyLog.d(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" handleParam  POST  ");
		} else {
			MyLog.i(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" HttpThread   ");
			urlConnection.setRequestMethod("GET");
		}
	}

	private boolean handleResponseHead() throws Exception {

		int reponseCode = urlConnection.getResponseCode();
		
		
		
		
		MyLog.w(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" handleResponseHead reponseCode = "+reponseCode);
		if (reponseCode != 200) {
			String responseMessage = urlConnection.getResponseMessage();
			String errorMsg = Tools.inputStream2String(urlConnection.getErrorStream());
			MyLog.e(TAG, "httpFrame  threadName:"+ Thread.currentThread().getName()+" handleResponseHead reponseCode = "+reponseCode+ "   responseMessage:"+responseMessage+"  errorMsg:"+errorMsg);
			urlConnection.disconnect();
			throw new Exception("缃戠粶璇锋眰閿欒");
		} else {
//			httpResponse.setResponseCode(HttpResponse.RESPONSE_CODE_SUCCESS);
//			httpResponse.setContentLength(urlConnection.getContentLength());
//			httpResponse.setContentType(urlConnection.getContentType());
//			httpResponse.setContentEncoding(urlConnection.getContentEncoding());
			return true;
		}
	}

	private HttpResponse handleResponseData(HttpRequest httpRequest) throws Exception {

		return httpRequest.onDoingExecute(urlConnection);
	}

	public HttpThreadListener getHttpThreadListener() {
		return mHttpThreadListener;
	}
	
	
}

interface HttpThreadListener {
	public HttpRequest getHttpRequest();

	public void finishHttpRequest(HttpRequest httpRequest);
	
	public void requestWait(HttpThread httpThread);
}
